import path from 'path';

import { CommonConst } from '../../../../../src/const/common-const';

import { ModuleTemplateOption } from './model-options';
import { AbsFileNode, DataNode, DirNode, DirTemplate } from './template-models';

/**
 * 模块类型
 */
export class Module {

  /**
   * 模块名称
   */
  readonly name: string;

  /**
   * 模板标签
   *
   * @type {ModuleTemplateOption}
   */
  readonly option: ModuleTemplateOption;

  /**
   * 模板对象
   *
   * @type {DirTemplate}
   */
  readonly template: DirTemplate;

  /**
   * 构建完成后生成的文件对象
   *
   * @type {DirNode<AbsFileNode<any, any>, any>}
   */
  public dirNode?: DirNode<AbsFileNode<any>>;

  /**
   * 配置初始化的方法
   *
   * @type {ModuleConfigInitFun}
   * @private
   */
  private readonly configInitFun: ModuleConfigInitFun;

  /**
   * 构造函数
   *
   * @param {DirTemplate} template
   * @param {ModuleTemplateOption} option
   * @param {ModuleConfigInitFun} init
   */
  constructor(template: DirTemplate, option: ModuleTemplateOption, init: ModuleConfigInitFun) {
    this.name = template.name;
    this.template = template;
    this.option = option;
    this.configInitFun = init;
  }

  /**
   * 更新属性值
   *
   * @param {Partial<ModuleTemplateOption>} option
   */
  public refreshOption(option: Partial<ModuleTemplateOption>) {
    for (const [key, value] of Object.entries(option)) {
      (this.option as any)[key] = value;
    }
  }

  /**
   * 构建module
   *
   * @param {string} target
   * @return {Promise<void>}
   */
  async build(target: string): Promise<void> {
    await this.configInitFun(this.name, this.option, this.template as DataNode<DataNode<any>>);
    this.dirNode = await this.template.generated(target);
    this.build = (target: string) => {
      throw new Error('The file has finished building and the function cannot be called again.');
    };
  }

  /**
   * 刷新文件
   *
   * @return {Promise<void>}
   */
  async refresh(update?: ModuleRefreshFun): Promise<void> {
    if (this.dirNode === undefined) {
      throw new Error('The file has not been built, please execute the build() function.');
    }
    await this.configInitFun(this.name, this.option, this.dirNode as DataNode<DataNode<any>>);

    if (update) {
      await update(this.name, this.option, this.dirNode);
    }
    await this.dirNode!.refresh();
  }

  /**
   * 获取模块根目录
   *
   * @return {string}
   */
  public moduleRootPath(): string {
    return this.dirNode!.path!;
  }

  /**
   * 获取模块src/main路径
   */
  public moduleSrcMainPath(): string {
    return path.resolve(this.moduleRootPath(), 'src', 'main');
  }

  /**
   * 获取模块module.json5路径
   */
  public moduleModuleJsonPath(): string {
    return path.resolve(this.moduleSrcMainPath(), `${CommonConst.MODULE_JSON5}`);
  }

  /**
   * 获取模块syscap.json路径
   */
  public moduleSysCapJsonPath(): string {
    return path.resolve(this.moduleSrcMainPath(), `${CommonConst.SYSCAP_JSON}`);
  }
}

/**
 * 初始化配置项
 */
export type ModuleConfigInitFun = (name: string, option: ModuleTemplateOption,
  template: DataNode<DataNode<any>>) => Promise<void>;

/**
 * 配置项刷新函数
 */
export type ModuleRefreshFun = (name: string, option: ModuleTemplateOption,
  dirNode: DirNode<AbsFileNode<any>>) => Promise<void>;
